<template>
  <div class="codeaudit-layout">
    <div class="left-middle-wrapper">
      <!-- 左侧列：代码输入 -->
      <div class="left-column">
      <section class="codeaudit-input-card">
        <div class="codeaudit-card-title">
          <h4>代码输入</h4>
          <button
            v-if="codeAuditFile || codeAuditText"
            type="button"
            class="btn ghost small"
            @click="clearCodeAuditInput"
          >
            清空全部
          </button>
        </div>

        <div class="codeaudit-input-body">
          <div
            class="codeaudit-dropzone"
            :class="{ 'drag-over': codeAuditDragOver }"
            @dragover.prevent="codeAuditDragOver = true"
            @dragleave="codeAuditDragOver = false"
            @drop="handleCodeAuditDrop"
            @click="triggerCodeAuditFileInput"
          >
            <input
              ref="codeAuditFileInput"
              type="file"
              accept=".zip,.tar,.gz,.tgz,.rar,.7z,.txt,.js,.ts,.py,.java,.c,.cpp,.go,.rs,.php"
              hidden
              @change="handleCodeAuditFileSelect"
            />

            <div v-if="!codeAuditFile" class="codeaudit-dropzone-placeholder">
              <span class="upload-icon" aria-hidden="true">📁</span>
              <p>点击或拖入代码压缩包/文件</p>
              <p class="hint">支持 zip、代码文本等常见格式</p>
            </div>

            <div v-else class="codeaudit-dropzone-file">
              <div class="file-info">
                <div class="file-name">{{ codeAuditFile.name }}</div>
                <div class="file-size">{{ formatFileSize(codeAuditFile.size) }}</div>
              </div>
              <button
                type="button"
                class="btn ghost small"
                @click.stop="removeCodeAuditFile"
              >
                移除文件
              </button>
            </div>
          </div>

          <div class="codeaudit-textarea">
            <label for="codeaudit-textarea">或直接粘贴代码片段</label>
            <textarea
              id="codeaudit-textarea"
              v-model="codeAuditText"
              rows="6"
              placeholder="在此粘贴需要审计的代码..."
            ></textarea>
            <div class="codeaudit-text-meta">
              <span>当前字符数：{{ codeAuditText.length }}</span>
              <button
                v-if="codeAuditText"
                type="button"
                class="btn ghost small"
                @click="codeAuditText = ''"
              >
                清空文本
              </button>
            </div>
          </div>
        </div>
      </section>
    </div>

    <!-- 中间列：审计配置 -->
    <div class="middle-column">
      <section class="codeaudit-config-card">
        <div class="codeaudit-card-title">
          <h4>审计配置</h4>
          <button
            v-if="codeAuditSelectedCategories.length || codeAuditSelectedItems.length"
            type="button"
            class="btn ghost small"
            @click="resetCodeAuditConfig"
          >
            重置配置
          </button>
        </div>

        <div class="codeaudit-config-grid">
          <div class="config-block">
            <label for="codeaudit-model">选择模型</label>
            <select id="codeaudit-model" v-model="codeAuditModel">
              <option
                v-for="model in codeAuditModelOptions"
                :key="model.value"
                :value="model.value"
              >
                {{ model.label }}
              </option>
            </select>
            <p class="config-hint" v-if="activeModelHint">{{ activeModelHint }}</p>
          </div>

          <div class="config-block">
            <label for="codeaudit-language">选择语言</label>
            <select id="codeaudit-language" v-model="codeAuditLanguage">
              <option
                v-for="lang in codeAuditLanguageOptions"
                :key="lang.value"
                :value="lang.value"
              >
                {{ lang.label }}
              </option>
            </select>
          </div>
        </div>

        <div class="config-block">
          <div class="config-block-header">
            <label>审计选项</label>
            <span class="config-hint">
              已选 {{ codeAuditSelectedCategories.length }} 类，{{ codeAuditSelectedItems.length }} 项
            </span>
          </div>

          <div
            v-if="codeAuditAvailableCategories.length"
            class="audit-option-groups"
          >
            <div
              v-for="category in codeAuditAvailableCategories"
              :key="category.id"
              class="audit-option-group"
            >
              <label class="audit-option-group-title">
                <input
                  type="checkbox"
                  :value="category.id"
                  v-model="codeAuditSelectedCategories"
                />
                <span>{{ category.label }}</span>
              </label>
              <p v-if="category.description" class="config-hint">{{ category.description }}</p>

              <div class="audit-option-items">
                <label
                  v-for="item in category.items"
                  :key="item.id"
                  class="audit-option-item"
                  :class="{ disabled: !codeAuditSelectedCategories.includes(category.id) }"
                >
                  <input
                    type="checkbox"
                    :value="item.id"
                    :disabled="!codeAuditSelectedCategories.includes(category.id)"
                    v-model="codeAuditSelectedItems"
                  />
                  <span class="item-label">{{ item.label }}</span>
                  <span v-if="item.severity" class="item-badge" :data-level="item.severity">
                    {{ item.severity.toUpperCase() }}
                  </span>
                </label>
              </div>
            </div>
          </div>

          <p v-else class="config-hint">请选择语言以查看可用的审计选项。</p>
        </div>
      </section>
    </div>

    <!-- 操作按钮区：横跨左侧和中间列 -->
    <section class="codeaudit-action-card">
      <div class="action-buttons">
        <button
          class="btn primary large"
          :disabled="!canSubmitCodeAudit || codeAuditRunning"
          @click="submitCodeAudit"
        >
          <span v-if="codeAuditRunning">审计中...</span>
          <span v-else>开始审计</span>
        </button>
        <button
          class="btn ghost large"
          :disabled="codeAuditRunning"
          @click="resetCodeAuditAll"
        >
          重置
        </button>
      </div>
      <p class="action-hint">
        上传文件或粘贴代码，并选择语言与审计选项后即可发起审计。
      </p>
    </section>
  </div>

  <!-- 右侧列：风险评分和审计结果 -->
  <div class="right-column">
      <!-- 有问题时显示风险评分卡 -->
      <risk-score-card
        v-if="codeAuditResults.length > 0"
        class="codeaudit-risk-card"
        :results="codeAuditResults"
      />
      
      <!-- 审计完成且有问题时显示结果列表 -->
      <section v-if="codeAuditResults.length > 0" class="codeaudit-result-card">
        <result-panel :results="codeAuditResultsNormalized" />
      </section>

      <!-- 审计完成但无问题时显示安全提示 -->
      <div v-else-if="auditCompleted && codeAuditResults.length === 0" class="safe-placeholder">
        <div class="safe-icon">✅</div>
        <p class="safe-title">代码安全</p>
        <p class="safe-text">未发现安全风险</p>
        <p class="safe-hint">已完成审计，代码符合安全规范</p>
      </div>

      <!-- 未开始审计时显示空状态 -->
      <div v-else class="empty-placeholder">
        <div class="empty-icon">📝</div>
        <p class="empty-text">暂无审计结果</p>
        <p class="empty-hint">完成审计后，详细结果将显示在这里</p>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'
import RiskScoreCard from '@/components/RiskScoreCard.vue'
import FileTree from '@/components/FileTree.vue'
import ResultPanel from '@/components/ResultPanel.vue'

// 代码审计服务独立端口
const AUDIT_API_BASE_URL = 'http://10.143.12.79:8043'

const codeAuditFileInput = ref<HTMLInputElement | null>(null)
const codeAuditFile = ref<File | null>(null)
const codeAuditText = ref('')
const codeAuditDragOver = ref(false)
const codeAuditModel = ref('finetune-merge-deepseek-8b')
const codeAuditLanguage = ref('')
const codeAuditSelectedCategories = ref<string[]>([])
const codeAuditSelectedItems = ref<string[]>([])
const codeAuditResults = ref<Array<Record<string, any>>>([])
const codeAuditRunning = ref(false)
const auditCompleted = ref(false)  // 记录是否完成过审计

const codeAuditModelOptions = computed(() => [
  { label: 'finetune-merge-deepseek-8b', value: 'finetune-merge-deepseek-8b', hint: '专业安全审计模型，覆盖 Web/系统/应用安全场景' },
])

const codeAuditLanguageOptions = computed(() => [
  { label: '自动检测', value: '' },
  { label: 'Java', value: 'java' },
  { label: 'Python', value: 'python' },
  { label: 'JavaScript', value: 'javascript' },
  { label: 'TypeScript', value: 'typescript' },
  { label: 'Go', value: 'go' },
  { label: 'PHP', value: 'php' },
  { label: 'C/C++', value: 'cpp' },
  { label: 'Rust', value: 'rust' },
])

const codeAuditOptionPresets: Record<string, Array<{ id: string; label: string; description?: string; items: Array<{ id: string; label: string; severity?: string }> }>> = {
  java: [
    {
      id: 'web-vulns',
      label: 'Web 漏洞检测',
      description: '涵盖常见 SQL 注入 / XSS / 反序列化等风险',
      items: [
        { id: 'sql-injection', label: 'SQL 注入', severity: 'high' },
        { id: 'xss', label: '跨站脚本', severity: 'high' },
        { id: 'ssrf', label: '服务端请求伪造', severity: 'critical' },
        { id: 'deserialization', label: '反序列化漏洞', severity: 'critical' },
      ],
    },
    {
      id: 'secure-coding',
      label: '安全编码规范',
      items: [
        { id: 'resource-release', label: '资源释放', severity: 'medium' },
        { id: 'input-validate', label: '输入校验', severity: 'medium' },
        { id: 'logging', label: '敏感日志输出', severity: 'low' },
      ],
    },
  ],
  python: [
    {
      id: 'py-sec',
      label: 'Python 安全检测',
      items: [
        { id: 'pickle', label: 'Pickle 反序列化', severity: 'critical' },
        { id: 'eval-exec', label: '危险内建函数使用', severity: 'high' },
        { id: 'path-traversal', label: '路径遍历', severity: 'high' },
        { id: 'subprocess', label: '命令执行风险', severity: 'critical' },
      ],
    },
    {
      id: 'best-practice',
      label: '最佳实践',
      items: [
        { id: 'logging-config', label: '日志配置', severity: 'low' },
        { id: 'typing', label: '类型提示建议', severity: 'info' },
      ],
    },
  ],
  javascript: [
    {
      id: 'frontend',
      label: '前端安全',
      description: '检测客户端 XSS / CSRF / 依赖漏洞等风险',
      items: [
        { id: 'xss', label: 'DOM XSS 风险', severity: 'high' },
        { id: 'csrf', label: 'CSRF 防护', severity: 'medium' },
        { id: 'dependency', label: '依赖风险', severity: 'medium' },
      ],
    },
    {
      id: 'nodejs',
      label: 'Node.js 服务',
      description: '涵盖原型链污染 / 命令注入等服务端风险',
      items: [
        { id: 'prototype-pollution', label: '原型链污染', severity: 'high' },
        { id: 'command-injection', label: '命令注入', severity: 'critical' },
      ],
    },
  ],
  default: [
    {
      id: 'general',
      label: '通用安全检查',
      items: [
        { id: 'hardcode-secret', label: '敏感信息硬编码', severity: 'high' },
        { id: 'weak-encryption', label: '弱加密算法', severity: 'medium' },
        { id: 'error-handling', label: '异常处理', severity: 'low' },
      ],
    },
  ],
}

const codeAuditAvailableCategories = computed(() => {
  if (!codeAuditLanguage.value) return codeAuditOptionPresets.default
  return codeAuditOptionPresets[codeAuditLanguage.value] || codeAuditOptionPresets.default
})

const codeAuditAvailableItemIds = computed(() => {
  const ids = new Set<string>()
  codeAuditAvailableCategories.value.forEach((category) => {
    category.items.forEach((item) => ids.add(item.id))
  })
  return ids
})

watch(codeAuditLanguage, () => {
  codeAuditSelectedCategories.value = []
  codeAuditSelectedItems.value = []
})

watch(codeAuditSelectedCategories, (selected) => {
  const allowed = new Set<string>()
  codeAuditAvailableCategories.value
    .filter((category) => selected.includes(category.id))
    .forEach((category) => {
      category.items.forEach((item) => allowed.add(item.id))
    })
  codeAuditSelectedItems.value = codeAuditSelectedItems.value.filter((id) => allowed.has(id))
}, { deep: true })

watch(codeAuditAvailableItemIds, (allowed) => {
  codeAuditSelectedItems.value = codeAuditSelectedItems.value.filter((id) => allowed.has(id))
})

const activeModelHint = computed(() => {
  const entry = codeAuditModelOptions.value.find((option) => option.value === codeAuditModel.value)
  return entry?.hint || ''
})

const codeAuditResultsNormalized = computed(() => {
  return codeAuditResults.value.map((result: any, index) => ({
    id: `result-${Date.now()}-${index}`,
    file: result.file || '未知文件',
    line: result.line || 0,
    severity: (result.severity || 'medium').toLowerCase(),
    type: result.type || '未知类型',
    description: result.description || '无描述',
    snippet: result.snippet || '',
    fix: result.fix || ''
  }))
})

const canSubmitCodeAudit = computed(() => {
  const hasInput = !!codeAuditFile.value || !!codeAuditText.value.trim()
  const hasLanguage = codeAuditLanguage.value !== undefined && codeAuditLanguage.value !== null
  const hasOptions = codeAuditSelectedCategories.value.length > 0 || codeAuditSelectedItems.value.length > 0
  return hasInput && hasLanguage && hasOptions
})

const formatFileSize = (size: number) => {
  if (!Number.isFinite(size)) return '0 B'
  const units = ['B', 'KB', 'MB', 'GB', 'TB']
  let value = size
  let unitIndex = 0
  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024
    unitIndex += 1
  }
  const displayed = value >= 100 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1)
  return `${displayed} ${units[unitIndex]}`
}

const triggerCodeAuditFileInput = () => {
  codeAuditFileInput.value?.click()
}

const handleCodeAuditFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (file) {
    codeAuditFile.value = file
  }
}

const handleCodeAuditDrop = (event: DragEvent) => {
  event.preventDefault()
  codeAuditDragOver.value = false
  const file = event.dataTransfer?.files[0]
  if (file) {
    codeAuditFile.value = file
  }
}

const removeCodeAuditFile = () => {
  codeAuditFile.value = null
  if (codeAuditFileInput.value) {
    codeAuditFileInput.value.value = ''
  }
}

const clearCodeAuditInput = () => {
  removeCodeAuditFile()
  codeAuditText.value = ''
}

const resetCodeAuditConfig = () => {
  codeAuditModel.value = codeAuditModelOptions.value[0]?.value || ''
  codeAuditLanguage.value = ''
  codeAuditSelectedCategories.value = []
  codeAuditSelectedItems.value = []
}

const resetCodeAuditAll = () => {
  clearCodeAuditInput()
  resetCodeAuditConfig()
  codeAuditResults.value = []
  auditCompleted.value = false  // 重置审计状态
}

const submitCodeAudit = async () => {
  if (!canSubmitCodeAudit.value || codeAuditRunning.value) return

  codeAuditRunning.value = true
  codeAuditResults.value = []
  auditCompleted.value = false  // 重置审计完成状态

  try {
    const formData = new FormData()

    if (codeAuditFile.value) {
      formData.append('file', codeAuditFile.value)
    }

    formData.append('language', codeAuditLanguage.value ?? '')
    formData.append('categories', JSON.stringify(codeAuditSelectedCategories.value))
    formData.append('items', JSON.stringify(codeAuditSelectedItems.value))
    formData.append('text_content', codeAuditText.value.trim())
    formData.append('model', codeAuditModel.value)

    const response = await fetch(`${AUDIT_API_BASE_URL}/api/audit`, {
      method: 'POST',
      body: formData,
    })

    const contentType = response.headers.get('content-type') || ''
    let payload: any = null

    if (contentType.includes('application/json')) {
      payload = await response.json()
    } else {
      const text = await response.text()
      try {
        payload = JSON.parse(text)
      } catch (e) {
        payload = { error: text }
      }
    }

    if (!response.ok) {
      const message = payload?.message || payload?.error || `HTTP ${response.status}`
      throw new Error(message)
    }

    const normalizedIssues = normalizeAuditIssues(payload)
    codeAuditResults.value = normalizedIssues
    auditCompleted.value = true  // 标记审计已完成

    if (!normalizedIssues.length) {
      console.info('[audit] 审计完成，未发现问题')
    }
  } catch (error: any) {
    console.error('代码审计失败:', error)
    if (typeof window !== 'undefined' && typeof window.alert === 'function') {
      window.alert(`审计失败：${error?.message || '未知错误'}`)
    }
  } finally {
    codeAuditRunning.value = false
  }
}

function normalizeAuditIssues(raw: any) {
  if (!raw) return []

  const dataSection = Array.isArray(raw)
    ? raw
    : Array.isArray(raw?.issues)
      ? raw.issues
      : Array.isArray(raw?.data?.issues)
        ? raw.data.issues
        : Array.isArray(raw?.data)
          ? raw.data
          : []

  if (!Array.isArray(dataSection)) return []

  return dataSection.map((issue, index) => {
    const severity = String(issue?.severity || 'medium').toLowerCase()
    const filePath = issue?.filePath || issue?.file || issue?.path || '未知文件'
    const lineNumber = Number.isFinite(Number(issue?.lineNumber ?? issue?.line))
      ? Number(issue?.lineNumber ?? issue?.line)
      : 0

    return {
      id: issue?.id || issue?.issueId || `issue-${Date.now()}-${index}`,
      file: filePath,
      line: lineNumber,
      severity,
      type: issue?.vulnerabilityType || issue?.type || issue?.title || '未知类型',
      description: issue?.description || issue?.detail || '无描述',
      snippet: issue?.codeSnippet || issue?.snippet || '',
      fix: issue?.fix || issue?.solution || issue?.recommendation || '',
      payload: issue?.payload || '',
    }
  })
}

const handleCodeAuditFileSelected = (path: string) => {
  console.log('Selected file from tree:', path)
}
</script>

<style scoped>
/* 三列布局 */
.codeaudit-layout {
  display: grid;
  grid-template-columns: 1fr 480px;
  gap: 20px;
  height: 100%;
  max-height: 100vh;
  overflow: hidden;
  padding: 0;
}

/* 左中区域包装器 */
.left-middle-wrapper {
  display: grid;
  grid-template-columns: 380px 1fr;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 20px;
  height: 100%;
  overflow: hidden;
}

/* 左侧列：代码输入 */
.left-column {
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow-y: auto;
  overflow-x: hidden;
  padding-right: 8px;
  grid-row: 1;
}

/* 代码输入卡片自动填充剩余空间 */
.codeaudit-input-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.codeaudit-input-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: 1;
  min-height: 0;
}

/* 文本域自动扩展 */
.codeaudit-textarea {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.codeaudit-textarea textarea {
  flex: 1;
  min-height: 150px;
  max-height: none;
  resize: none;
}

/* 中间列：审计配置 */
.middle-column {
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0 8px;
  grid-row: 1;
  max-height: 100%;
}

/* 审计配置卡片 */
.codeaudit-config-card {
  background: #fff;
  border: 1px solid var(--ui-border, #e5e7eb);
  border-radius: 12px;
  padding: 16px;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

/* 操作按钮区：横跨两列 */
.codeaudit-action-card {
  grid-column: 1 / -1;
  grid-row: 2;
  background: #fff;
  border: 1px solid var(--ui-border, #e5e7eb);
  border-radius: 12px;
  padding: 20px;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
  flex-shrink: 0;
  z-index: 10;
}

/* 右侧列：审计结果 */
.right-column {
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
  padding-left: 8px;
}

/* 美化滚动条 */
.left-column::-webkit-scrollbar,
.middle-column::-webkit-scrollbar,
.right-column::-webkit-scrollbar {
  width: 8px;
}

.left-column::-webkit-scrollbar-track,
.middle-column::-webkit-scrollbar-track,
.right-column::-webkit-scrollbar-track {
  background: #f1f5f9;
  border-radius: 4px;
}

.left-column::-webkit-scrollbar-thumb,
.middle-column::-webkit-scrollbar-thumb,
.right-column::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 4px;
  transition: background 0.2s ease;
}

.left-column::-webkit-scrollbar-thumb:hover,
.middle-column::-webkit-scrollbar-thumb:hover,
.right-column::-webkit-scrollbar-thumb:hover {
  background: #94a3b8;
}

.codeaudit-input-card,
.codeaudit-config-card,
.codeaudit-result-card {
  background: #fff;
  border: 1px solid var(--ui-border, #e5e7eb);
  border-radius: 12px;
  padding: 16px;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
}

.codeaudit-card-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  flex-shrink: 0;
}

.codeaudit-card-title h4 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #1f2937;
}

.codeaudit-input-body {
  display: grid;
  gap: 12px;
}

.codeaudit-dropzone {
  border: 1px dashed var(--ui-border, #cbd5f5);
  background: #f8fafc;
  border-radius: 12px;
  padding: 16px;
  text-align: center;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  min-height: 100px;
  flex-shrink: 0;
}

.codeaudit-dropzone:hover,
.codeaudit-dropzone.drag-over {
  border-color: #3b82f6;
  background: rgba(59, 130, 246, 0.08);
}

.codeaudit-dropzone-placeholder p {
  margin: 0;
  color: #4b5563;
}

.codeaudit-dropzone-placeholder .hint {
  font-size: 12px;
  color: #6b7280;
}

.codeaudit-dropzone-file {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.codeaudit-dropzone-file .file-info {
  text-align: left;
}

.codeaudit-dropzone-file .file-name {
  font-weight: 600;
  color: #1f2937;
}

.codeaudit-dropzone-file .file-size {
  font-size: 12px;
  color: #6b7280;
}

.codeaudit-textarea label {
  display: block;
  font-weight: 600;
  color: #1f2937;
  margin-bottom: 8px;
  flex-shrink: 0;
}

.codeaudit-textarea textarea {
  width: 100%;
  border: 1px solid var(--ui-border, #d1d5db);
  border-radius: 10px;
  padding: 10px;
  font-family: 'JetBrains Mono', 'Courier New', monospace;
  font-size: 13px;
  line-height: 1.6;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
  overflow-y: auto;
}

.codeaudit-textarea textarea:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

.codeaudit-text-meta {
  margin-top: 6px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  color: #6b7280;
  font-size: 12px;
}

.btn.small {
  height: 30px;
  padding: 0 12px;
  font-size: 12px;
}

.btn.large {
  height: 44px;
  padding: 0 18px;
  font-size: 15px;
  border-radius: 12px;
}

.upload-icon {
  font-size: 32px;
}

.codeaudit-config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
}

.config-block label {
  display: block;
  font-weight: 600;
  color: #1f2937;
  margin-bottom: 6px;
}

.config-block select {
  width: 100%;
  height: 40px;
  border-radius: 10px;
  border: 1px solid var(--ui-border, #d1d5db);
  padding: 0 12px;
  background: #fff;
  font-size: 14px;
  color: #1f2937;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.config-block select:focus {
  outline: none;
  border-color: #3b82f6;
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15);
}

.config-block-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
}

.config-hint {
  font-size: 12px;
  color: #6b7280;
}

.audit-option-groups {
  display: grid;
  gap: 12px;
  max-height: 450px;
  overflow-y: auto;
  padding-right: 4px;
}

/* 审计选项组滚动条 */
.audit-option-groups::-webkit-scrollbar {
  width: 6px;
}

.audit-option-groups::-webkit-scrollbar-track {
  background: #f1f5f9;
  border-radius: 3px;
}

.audit-option-groups::-webkit-scrollbar-thumb {
  background: #cbd5e1;
  border-radius: 3px;
}

.audit-option-groups::-webkit-scrollbar-thumb:hover {
  background: #94a3b8;
}

.audit-option-group {
  border: 1px solid #e5e7eb;
  border-radius: 10px;
  padding: 12px;
  background: #f9fafb;
}

.audit-option-group-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  color: #1f2937;
  margin-bottom: 6px;
}

.audit-option-items {
  display: grid;
  gap: 6px;
  margin-top: 6px;
}

.audit-option-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px;
  border-radius: 8px;
  background: #fff;
  border: 1px solid transparent;
  transition: border-color 0.2s ease, background 0.2s ease;
}

.audit-option-item input {
  flex-shrink: 0;
}

.audit-option-item .item-label {
  flex: 1;
  color: #1f2937;
}

.audit-option-item.disabled {
  opacity: 0.6;
}

.audit-option-item:not(.disabled):hover {
  border-color: #3b82f6;
  background: rgba(59, 130, 246, 0.08);
}

.item-badge {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 6px;
  border-radius: 999px;
  background: #e5e7eb;
  color: #111827;
}

.item-badge[data-level="critical"] {
  background: #fee2e2;
  color: #b91c1c;
}

.item-badge[data-level="high"] {
  background: #ffedd5;
  color: #c2410c;
}

.item-badge[data-level="medium"] {
  background: #fef3c7;
  color: #b45309;
}

.item-badge[data-level="low"] {
  background: #dcfce7;
  color: #15803d;
}

.item-badge[data-level="info"] {
  background: #e0f2fe;
  color: #0369a1;
}

.action-buttons {
  display: flex;
  gap: 20px;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}

.action-buttons .btn {
  flex: 1;
  min-width: 180px;
  max-width: 300px;
}

.action-hint {
  margin-top: 8px;
  text-align: center;
  font-size: 13px;
  color: #6b7280;
}

.codeaudit-risk-card {
  /* 不需要margin */
}

/* 空状态样式 */
.empty-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 20px;
  text-align: center;
  background: linear-gradient(135deg, #f8fafc 0%, #ffffff 100%);
  border-radius: 16px;
  border: 2px dashed #e5e7eb;
  min-height: 400px;
}

.empty-icon {
  font-size: 64px;
  margin-bottom: 16px;
  opacity: 0.6;
}

.empty-text {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 600;
  color: #374151;
}

.empty-hint {
  margin: 0;
  font-size: 14px;
  color: #9ca3af;
  line-height: 1.6;
  max-width: 300px;
}

/* 安全提示样式 */
.safe-placeholder {
  background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
  border: 2px solid #86efac;
  border-radius: 16px;
  padding: 48px 32px;
  text-align: center;
  min-height: 300px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

.safe-icon {
  font-size: 64px;
  margin-bottom: 8px;
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.1); }
}

.safe-title {
  margin: 0;
  font-size: 24px;
  font-weight: 700;
  color: #15803d;
}

.safe-text {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 600;
  color: #166534;
}

.safe-hint {
  margin: 0;
  font-size: 14px;
  color: #4ade80;
  line-height: 1.6;
  max-width: 300px;
}

/* 响应式布局 */
@media (max-width: 1400px) {
  .left-middle-wrapper {
    grid-template-columns: 340px 1fr;
  }
  
  .codeaudit-layout {
    grid-template-columns: 1fr 420px;
  }
}

@media (max-width: 1200px) {
  .left-middle-wrapper {
    grid-template-columns: 320px 1fr;
  }
  
  .codeaudit-layout {
    grid-template-columns: 1fr 380px;
  }
}

@media (max-width: 960px) {
  .codeaudit-layout {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    max-height: none;
  }
  
  .left-middle-wrapper {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto auto;
  }
  
  .left-column,
  .middle-column,
  .right-column {
    overflow-y: visible;
    max-height: none;
  }
  
  .action-buttons .btn {
    min-width: 120px;
  }
}
</style>
